package model;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Embeddable;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Transient;

import org.eclipse.jdt.internal.compiler.ast.ThisReference;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;

import viewObjects.FechaVO;

import exceptions.FechaException;
@Embeddable
public class Fixture {
	@OneToMany(cascade= CascadeType.ALL)
	@LazyCollection(LazyCollectionOption.FALSE)
	@JoinColumn(name="idCategoria")
	private List<Regular> fechasRegulares;

	@OneToMany(cascade= CascadeType.ALL )
	@JoinColumn(name="idCategoria")
	private List<Playoff> fechasPlayoff;
	
	public Fixture(){
		fechasRegulares = new ArrayList<Regular>();
		fechasPlayoff = new ArrayList<Playoff>();
	}

	public Fixture(int id,Date fechaInicio ){
		fechasRegulares = new ArrayList<Regular>();
		fechasPlayoff = new ArrayList<Playoff>();
	}

	public List<Regular> getFechasRegulares() {
		return fechasRegulares;
	}

	public void addFechaRegular(Regular fechaRegular) {
		this.fechasRegulares.add(fechaRegular);
	}
	
	public void addFechasRegulares(ArrayList<Regular> fechasRegulares) {
		this.fechasRegulares.addAll(fechasRegulares);
	}

	public List<Playoff> getFechasPlayoff() {	
		return fechasPlayoff;
	}

	public void addFechaPlayoff(Playoff fechaPlayoff) {
		this.fechasPlayoff.add(fechaPlayoff);
	}
	
	public void addFechasPlayoff(ArrayList<Playoff> fechasPlayoff) {
		this.fechasPlayoff.addAll(fechasPlayoff);
	}

	public FechaVO generarPlayoff(String instancia, Date fechaInicio, ArrayList<Posicion> posiciones, ArrayList<Sede> sedesPermitidas) throws FechaException {		
		Playoff fecha = null;
		int nroFechaNueva = this.getUltimoNumeroFecha() + 1;
		
		if (instancia.equals(constants.Instancia.OCTAVOS)){
			//Ordeno Posiciones
			Collections.sort(posiciones, new Comparator<Posicion>() {
			    public int compare(Posicion p1, Posicion p2) {
			        return Integer.valueOf(p1.getPuntos()).compareTo(Integer.valueOf(p2.getPuntos()));
			    }
			});
			
			//verifico que sean minimo 16
			if (posiciones.size() >= 16){
				//verifico que se hayan disputado todas las fechas regulares
				if (this.fechasRegularesDisputadas()){
					fecha = new Playoff(nroFechaNueva,fechaInicio,instancia);				
				
					int j = 15;
					int i = 0;
					while (i-j > 1){
						fecha.generarPartido(posiciones.get(i).getEquipo(), posiciones.get(j).getEquipo(),sedesPermitidas);
						j--;
						i++;
					}					
					this.addFechaPlayoff(fecha);
				}else{
					throw new FechaException("no estan todos los partidos disputados");
				}
			}else{
				throw new FechaException("no hay equipos suficientes");
			}
		}else{
			//ver que los partidos de la instancia anterior esten disputados
			String anteriorInstancia = constants.Instancia.anteriorInstancia(instancia);
			if (anteriorInstancia != null){
				if (this.fechasPlayoffDisputada(anteriorInstancia)){
					fecha = new Playoff(nroFechaNueva,fechaInicio,instancia);
					this.addFechaPlayoff(fecha);
				}else{
					throw new FechaException("no estan todos los partidos disputados");
				}
			}else{
				throw new FechaException("no se puede generar la instancia");
			}
		}
		
		if (fecha == null)
			throw new FechaException("no estan todos los partidos disputados");			
			
		return null;
		//return fecha.getView();	
	}
	
	private boolean fechasRegularesDisputadas(){
		boolean ret = true;
		for(Fecha fecha : this.fechasRegulares){
			if (!fecha.partidosDisputados()){
				ret = false;
			}
		}
		return ret;
	}
	
	private boolean fechasPlayoffDisputada(String instancia){
		boolean ret = true;
		for(Playoff fecha : this.fechasPlayoff){
			if (fecha.getInstancia().equals(instancia)){
				if (!fecha.partidosDisputados()){
					ret = false;
				}
			}
		}
		return ret;
	}
	
	private int getUltimoNumeroFecha(){
		int maxNroFecha = 0;
		
		if (this.fechasPlayoff.size() > 0){
			for(Fecha fecha : this.fechasPlayoff){
				if (fecha.getNroFecha() > maxNroFecha){
					maxNroFecha = fecha.getNroFecha();
				}
			}
		}else{
			for(Fecha fecha : this.fechasRegulares){
				if (fecha.getNroFecha() > maxNroFecha){
					maxNroFecha = fecha.getNroFecha();
				}
			}
		}
		
		return maxNroFecha;
	}	
	
	public Fixture(ArrayList<Equipo> equiposParticipantes, Date fechaInicio){
		
		if(equiposParticipantes.size() % 2 == 1){
			Equipo e = new Equipo();
			e.setNombre("LIBRE");
			equiposParticipantes.add(e);
		}
		ArrayList<Partido> partidos = new ArrayList<Partido>();		
	
		//Genero Partidos
		for (int i = 0; i < equiposParticipantes.size(); i++){
			for (int j = i + 1; j < equiposParticipantes.size(); j++){
				Partido p = new Partido(equiposParticipantes.get(i),equiposParticipantes.get(j));
				partidos.add(p);
			}
		}
		System.out.println("cant partidos" + partidos.size());
		//Verifico que sea sabado, o voy al primer sabado siguiente
		if (fechaInicio.getDay() != 6){
			Calendar c = Calendar.getInstance(); 
			c.setTime(fechaInicio); 
			c.add(Calendar.DATE, 6 - fechaInicio.getDay());
			fechaInicio = c.getTime();
		}
		
		//Asigno partidos a fechas
		int n = 1;
		fechasRegulares = new ArrayList<Regular>();
		
		ArrayList<Partido> partidosAsignados = new ArrayList<Partido>();
		int id = 0;
		while (n < equiposParticipantes.size() ){
			Regular fecha = new Regular(n, fechaInicio);
			id++;
			fecha.setId(id);
				for (Partido p : partidos){
					if (! fecha.estanEquiposEnFecha(p.getEquipoL(), p.getEquipoV())){
						fecha.addPartido(p);
						partidosAsignados.add(p);
					}
				}			
			System.out.println("fecha " + n + " " + partidosAsignados.size());
			partidos.removeAll(partidosAsignados);
			partidosAsignados.clear();
			
			this.addFechaRegular(fecha);
			
			Calendar c = Calendar.getInstance(); 
			c.setTime(fechaInicio); 
			c.add(Calendar.DATE, 7);
			fechaInicio = c.getTime();
			n++;
		}
		for(Fecha f : this.fechasRegulares){
			System.out.println(f.getNroFecha());
			for(Partido p :f.getPartidos()){
				System.out.println(p.getEquipoL().getNombre() + "  " + p.getEquipoV().getNombre()  );
			}
		}
		System.out.println("regs " + this.fechasRegulares.size());
	}

	
//	public boolean asignarSedePartidos(ArrayList<Sede> sedes){
//		
//		for (Fecha f : this.fechasRegulares){
//			Date fechaInicio = f.getFechaInicio();
//			
//			for (Partido p : f.getPartidos()){
//				ArrayList<Preferencia> sedesFinales = p.getSedesPreferentes();
//				Collections.sort(sedesFinales, new PreferenciasComparator());
//				
//				//Empiezo a asignar fechas y horarios de partidos
//				for (Preferencia pref : sedesFinales){
//					//Verifico que este dentro de la seleccion
//					if (sedes.contains(pref.getSede())){
//						Date fechaProgramacion = pref.getSede().puedo(fechaInicio);
//						
//						if (fechaProgramacion != null){
//							p.setFecha(fechaProgramacion);
//						}
//					}
//				}
//				
//				if (p.getFecha() == null){
//					return false;
//				}
//			}			
//		}
//		
//		return true;
//	}
//	
//	public boolean asignarArbitros(ArrayList<Arbitro> arbitros){
//		
//		for (Fecha f : this.fechasRegulares){	
//			for (Partido p : f.getPartidos()){		
//				
//				int arbitrosAsignados = 0;	
//				//BUSCO DOS QUE YA ESTEN ASIGANDOS A LA SEDE
//				for (Arbitro a : arbitros){
//					if (a.tenesFechaSede(p.getFecha(), p.getSede())){
//						if (arbitrosAsignados == 0){
//							p.setArbitro1(a);
//							arbitrosAsignados = 1;
//						}else{
//							p.setArbitro2(a);
//							arbitrosAsignados = 2;
//							break;
//						}
//					}
//				}
//				
//				//CASO EN QUE NO ENCONTRE 2 QUE YA ESTEN ASIGNADOS
//				if (arbitrosAsignados < 2){
//					for (Arbitro a : arbitros){
//						if (! a.tenesFecha(p.getFecha(), p.getSede())){
//							if (arbitrosAsignados == 0){
//								p.setArbitro1(a);
//								arbitrosAsignados = 1;
//							}else{
//								p.setArbitro2(a);
//								arbitrosAsignados = 2;
//								break;
//							}
//						}
//					}
//				}
//				
//				if (arbitrosAsignados < 2){
//					return false;
//				}
//			}			
//		}
//		
//		return true;
//	}
//
//	public FixtureView getView(){
//		FixtureView fV = new FixtureView();
//		
//		for(Fecha f : this.fechasRegulares){
//			fV.addFecha(f.getView());
//		}
//		
//		for(Fecha f : this.fechasPlayoff){
//			fV.addFecha(f.getView());
//		}
//		
//		return fV;
//	}	
//	
//	public FechaView generarFechaPlayoff(String instancia, ArrayList<Posicion> posiciones, ArrayList<Arbitro> arbitros){
//		Playoff ultimaInstancia = getUltimaInstancia();
//		
//		if (ultimaInstancia != null){
//			if (ultimaInstancia.fueDisputada()){
//				//CASO EN QUE FUE DISPUTADA LA ULTIMA INSTANCIA DE PLAYOFF
//			}
//		}else{
//			Regular ultimaFecha = getUltimaFecha();			
//			if (ultimaFecha != null){
//				if (ultimaFecha.fueDisputada()){
//					//CASO EN QUE FUE DISPUTADA LA ULTIMA FECHA REGULAR
//					if (instancia.toUpperCase().equals(Instancia.OCTAVOS) && posiciones.size() >= 16){
//						//SI TERMINE REGULAR SOLO DEJO CREAR OCTAVOS y SON MAS DE 16 EQUIPOS
//						Playoff fecha = new Playoff(ultimaFecha.getNroFecha(),Calendar.getInstance().getTime(),instancia.toUpperCase());
//						
//						Collections.sort(posiciones, new PosicionesComparator());
//						//OBTENGO CLASIFICADOS y ARMO CRUCES (0vs15, 1vs14, 2vs13...)
//						for (int i = 0; i < 8; i++){
//							Partido p = new Partido(posiciones.get(i).getEquipo(), posiciones.get(15-i).getEquipo());
//							fecha.addPartido(p);		
//							
//							//ASIGNAR SEDE
//							//Verifico que sea sabado, o voy al primer sabado siguiente
//							try{
//							DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy"); 				
//							String hoyS = formatter.format(Calendar.getInstance().getTime());
//							Date primerPartido = formatter.parse(hoyS);
//							
//							if (primerPartido.getDay() != 6){	
//								Calendar c = Calendar.getInstance();
//								c.setTime(primerPartido);
//								c.add(Calendar.DATE, 6 - primerPartido.getDay());
//								primerPartido = c.getTime();
//							}			
//							
//							ArrayList<Preferencia> sedesFinales = p.getSedesPreferentes();
//							Collections.sort(sedesFinales, new PreferenciasComparator());
//							
//							//Empiezo a asignar fechas y horarios de partidos
//							for (Preferencia pref : sedesFinales){
//								Date fechaProgramacion = pref.getSede().puedo(primerPartido);
//									
//								if (fechaProgramacion != null){
//									p.setFecha(fechaProgramacion);
//								}
//							}
//							
//							if (p.getFecha() == null){
//								return null;
//							}
//							
//							//ARBITRO
//							int arbitrosAsignados = 0;	
//							//BUSCO DOS QUE YA ESTEN ASIGANDOS A LA SEDE
//							for (Arbitro a : arbitros){
//								if (a.tenesFechaSede(p.getFecha(), p.getSede())){
//									if (arbitrosAsignados == 0){
//										p.setArbitro1(a);
//										arbitrosAsignados = 1;
//									}else{
//										p.setArbitro2(a);
//										arbitrosAsignados = 2;
//										break;
//									}
//								}
//							}
//							
//							//CASO EN QUE NO ENCONTRE 2 QUE YA ESTEN ASIGNADOS
//							if (arbitrosAsignados < 2){
//								for (Arbitro a : arbitros){
//									if (! a.tenesFecha(p.getFecha(), p.getSede())){
//										if (arbitrosAsignados == 0){
//											p.setArbitro1(a);
//											arbitrosAsignados = 1;
//										}else{
//											p.setArbitro2(a);
//											arbitrosAsignados = 2;
//											break;
//										}
//									}
//								}
//							}
//							
//							if (arbitrosAsignados < 2){
//								return null;
//							}
//							
//							}catch (Exception e){
//								return null;							
//							}
//						
//						}
//						
//						return fecha.getView();
//					}
//				}
//			}
//		}
//		
//		return null;
//	}
//	
//	private Playoff getUltimaInstancia(){
//		int maxNroFecha = -1;
//		Playoff ultima = null;
//		
//		for (Playoff f : this.fechasPlayoff){
//			if (f.getNroFecha() > maxNroFecha){
//				maxNroFecha = f.getNroFecha();
//				ultima = f;
//			}
//		}
//		
//		return ultima;	
//	}
//	
//	private Regular getUltimaFecha(){
//		int maxNroFecha = -1;
//		Regular ultima = null;
//		
//		for (Regular f : this.fechasRegulares){
//			if (f.getNroFecha() > maxNroFecha){
//				maxNroFecha = f.getNroFecha();
//				ultima = f;
//			}
//		}
//		
//		return ultima;
//	}
//	
//	public class PartidosPromComparator implements Comparator<Partido> {
//        @Override
//        public int compare(Partido p1, Partido p2) {
//            if (p1.getPromedioPartido() == p2.getPromedioPartido()){
//            	return 0;
//            }else if (p1.getPromedioPartido() > p2.getPromedioPartido()){
//            	return 1;
//            }else{
//            	return -1;
//            }
//        }
//    }	
//	
//	public class PreferenciasComparator implements Comparator<Preferencia> {
//        @Override
//        public int compare(Preferencia p1, Preferencia p2) {
//            if (p1.getNroFechaPreferencia() == p2.getNroFechaPreferencia()){
//            	return 0;
//            }else if (p1.getNroFechaPreferencia() > p2.getNroFechaPreferencia()){
//            	return 1;
//            }else{
//            	return -1;
//            }
//        }
//    }	
//	
//	public class PosicionesComparator implements Comparator<Posicion> {
//        @Override
//        public int compare(Posicion p1, Posicion p2) {
//            if (p1.getPuntos() == p2.getPuntos()){
//            	if (p1.getGolesFavor() - p1.getGolesContra() < p2.getGolesFavor() - p2.getGolesContra()){
//            		return 1;
//            	}else{
//            		return -1;
//            	}
//            }else if (p1.getPuntos() < p2.getPuntos()){
//            	return 1;
//            }else{
//            	return -1;
//            }
//        }
//    }
//
//	public ArrayList<Estadistica> estadisticasJugador(String id) {
//
//		ArrayList<Estadistica> estadisticas = new ArrayList<Estadistica>();
//		
//		for ( Fecha f : fechasRegulares){
//			
//			Estadistica e = f.estadisticasJugador(id); //busca el partido del jugador en la fecha
//			
//			if (e!=null)
//				estadisticas.add(e);
//			
//			
//		}
//		
//		for ( Fecha f : fechasPlayoff){
//			
//			Estadistica e = f.estadisticasJugador(id); //busca el partido del jugador en la fecha
//			
//			if (e!=null)
//				estadisticas.add(e);
//			
//			
//		}
//		
//		return estadisticas ;
//	}
//	
//
//	public ArrayList<Equipo> getFechas() {
//		
//		return null;
//	}
}
